home *** CD-ROM | disk | FTP | other *** search
/ United Public Domain Gold 2 / United Public Domain Gold 2.iso / education / pe023.dms / pe023.adf / BSPLINES / BSPLINE.C < prev    next >
C/C++ Source or Header  |  1988-10-05  |  9KB  |  425 lines

  1.  
  2. /*
  3.  *  BSPLINE.C
  4.  *
  5.  *  Matthew Dillon.
  6.  *  Public Domain (no Copyrights whatsoever)
  7.  *
  8.  *  -Assumes AZTEC compilation,  +L (32 bit ints), with all AMIGA symbols
  9.  *  precompiled.  Additionally expects certain typedefs and routines
  10.  *  found in MY.LIB, as well as some MY.LIB #include files.
  11.  *
  12.  *  An experienced programmer can remove the MY.LIB dependancies
  13.  *  (openlibs() call), and figure out what typedefs have been assumed if
  14.  *  he wishes to compile the program.  You can also simply extract the
  15.  *  Bezier functions for your own use.
  16.  *
  17.  *  BSPLINE EQUATIONS:
  18.  *
  19.  *    c(t) = T(t)BP
  20.  *
  21.  *    T(t) = (t^3 t^2 t 1)        P= ( Pi-1 )
  22.  *    B = (  -1   3  -3   1    )       ( Pi   )
  23.  *        (    3  -6    3   0    )       ( Pi+1 )
  24.  *        (  -3   0    3   0    )       ( Pi+2 )
  25.  *        (    1   4    1   0    )
  26.  *
  27.  *    t:  range 0 to 1
  28.  *    C:  coordinate matrix  1xD matrix (D = dimensions)
  29.  *    B:  Bspline matrix     4x4
  30.  *    P:  Ctrl. Point matrix 4xD matrix (D = dimensions)
  31.  *
  32.  *    using D = 2.  For B-Spline, must loop through all control points
  33.  *    beginning at Pi+1 and ending at Pend-2
  34.  */
  35.  
  36. #include <typedefs.h>
  37. #include <xmisc.h>
  38.  
  39. #define     SHIFTS  9
  40. #define     ONE     (1<<SHIFTS)
  41. #define     MAXPTS  256     /* Maximum # of bspline points allowed    */
  42.  
  43. typedef struct PropInfo XPI;
  44. typedef struct Image    IM;
  45.  
  46. extern IMESS *GetMsg();
  47.  
  48. #define MYGADGETS   (WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE)
  49.  
  50. NW Nw = {
  51.     64, 64, 320, 100,
  52.     0, 1,
  53.     NEWSIZE|MOUSEBUTTONS|MOUSEMOVE|CLOSEWINDOW|GADGETDOWN|GADGETUP|MENUPICK,
  54.     MYGADGETS|REPORTMOUSE|ACTIVATE|NOCAREREFRESH,
  55.     0, 0, (UBYTE *)"Bspline, By Matthew Dillon", NULL, NULL,
  56.     32, 64, -1, -1, WBENCHSCREEN
  57. };
  58.  
  59. WIN *Win;
  60. RP  *Rp;
  61. short Ux, Uy, Lx, Ly;
  62. short Step = 128;
  63. short Display = 1;
  64.  
  65. short Pts[MAXPTS+1][2], Npts;
  66.  
  67. main(ac, av)
  68. char *av[];
  69. {
  70.     register IMESS *mess;
  71.     short notdone = 1;
  72.     short pt = -1;
  73.     char mode = 0;        /* 0=move pts, 1=add pts, 2=del pts     */
  74.  
  75.     short gy, gg = 0;
  76.     XPI *po;
  77.  
  78.     init_gadgets(&Nw, &po);
  79.     exiterr(!openlibs(INTUITION_LIB|GRAPHICS_LIB), "unable to open libs");
  80.     exiterr(!(Win = OpenWindow(&Nw)), "unable to open window");
  81.     init_menu(Win);
  82.     Rp = Win->RPort;
  83.     SetAPen(Rp, 3);
  84.     SetDrMd(Rp, COMPLEMENT);
  85.     setpoint(Pts, 0, 32, 32);
  86.     setpoint(Pts, 1, 40, 40);
  87.     setpoint(Pts, 2, 100, 50);
  88.     setpoint(Pts, 3, 200, 60);
  89.     Npts = 4;
  90.     setbounds(Pts, Npts);
  91.     while (notdone) {
  92.     short mx, my, mm = 0;
  93.     WaitPort(Win->UserPort);
  94.     while (mess = GetMsg(Win->UserPort)) {
  95.         switch(mess->Class) {
  96.         case CLOSEWINDOW:
  97.         notdone = 0;
  98.         break;
  99.         case NEWSIZE:
  100.         setbounds(Pts, Npts);
  101.         break;
  102.         case GADGETUP:
  103.         case GADGETDOWN:
  104.         {
  105.             gg = mess->Class;
  106.             gy = po->VertPot / 256;
  107.         }
  108.         break;
  109.         case MOUSEBUTTONS:
  110.         switch(mess->Code) {
  111.         case SELECTDOWN:
  112.             pt = getpoint(Pts, Npts, mess->MouseX, mess->MouseY);
  113.             switch(mode) {
  114.             case 0:
  115.             mm = 1;
  116.             mx = mess->MouseX;
  117.             my = mess->MouseY;
  118.             goto break2;
  119.             case 1:
  120.             if (pt < 0)
  121.                 pt = 0;
  122.             if (Npts != MAXPTS) {
  123.                 bmov(Pts[pt], Pts[pt+1], (Npts-pt)*sizeof(Pts[0]));
  124.                 Pts[pt][0] = mess->MouseX;
  125.                 Pts[pt][1] = mess->MouseY;
  126.                 ++Npts;
  127.             }
  128.             break;
  129.             case 2:
  130.             if (pt >= 0 && pt < Npts) {
  131.                 bmov(Pts[pt+1], Pts[pt], (Npts-pt)*sizeof(Pts[0]));
  132.                 --Npts;
  133.             }
  134.             break;
  135.             }
  136.             clearall();
  137.             drawcurve(Pts, Npts);
  138.             drawpoints(Pts, 0, Npts);
  139.             break;
  140.         case SELECTUP:
  141.             pt = -1;
  142.             break;
  143.         }
  144. break2:
  145.         break;
  146.         case MENUPICK:
  147.         switch(MENUNUM(mess->Code)) {
  148.         case 0:
  149.             mode = ITEMNUM(mess->Code);
  150.             break;
  151.         case 1:
  152.             drawpoints(Pts, 0, Npts);
  153.             Display = ITEMNUM(mess->Code);  /* 0=cross 1=nums    */
  154.             drawpoints(Pts, 0, Npts);
  155.         }
  156.         break;
  157.         case MOUSEMOVE:
  158.         if (gg == GADGETDOWN) {
  159.             gy = po->VertPot / 256;
  160.             break;
  161.         }
  162.         if (mode == 0 || mode == 1) {
  163.             mm = 1;
  164.             mx = mess->MouseX;
  165.             my = mess->MouseY;
  166.         }
  167.         break;
  168.         default:
  169.         break;
  170.         }
  171.         ReplyMsg(mess);
  172.     }
  173.     if (mm && pt >= 0) {
  174.         register int i;
  175.         register int n;
  176.  
  177.         i = (pt - 3 < 0) ? 0 : pt - 3;
  178.         n = (i + 7 > Npts) ? Npts - i : 7;
  179.         drawpoints(Pts, pt, pt+1);
  180.         drawcurve(&Pts[i], n);
  181.         setpoint(Pts, pt, mx, my);
  182.         drawcurve(&Pts[i], n);
  183.         drawpoints(Pts, pt, pt+1);
  184.     }
  185.     if (gg) {
  186.         char buf[32];
  187.         if (gg == GADGETUP)
  188.         gg = 0;
  189.         if (gy + 1 >= 0 && gy + 1 != Step) {
  190.         Step = gy + 1;
  191.         sprintf(buf, "gran: %4ld/%ld", Step, ONE);
  192.         clearall();
  193.         drawcurve(Pts, Npts);
  194.         drawpoints(Pts, 0, Npts);
  195.         Move(Rp, Ux + 1, Uy + 16);
  196.         Text(Rp, buf, strlen(buf));
  197.         }
  198.     }
  199.     }
  200.     exiterr(1, NULL);
  201. }
  202.  
  203. exiterr(n, str)
  204. char *str;
  205. {
  206.     if (n) {
  207.     if (str)
  208.         puts(str);
  209.     if (Win) {
  210.         uninit_menu(Win);
  211.         CloseWindow(Win);
  212.     }
  213.     closelibs(-1);
  214.     exit(1);
  215.     }
  216. }
  217.  
  218. setbounds(a, na)
  219. register long *a;
  220. {
  221.     Ux = Win->BorderLeft;
  222.     Uy = Win->BorderTop;
  223.     Lx = Win->Width - Win->BorderRight;
  224.     Ly = Win->Height- Win->BorderBottom + 1;
  225.     clearall();
  226.     drawcurve(a, na);
  227.     drawpoints(a, 0, na);
  228. }
  229.  
  230. setpoint(a, pt, x, y)
  231. register short a[4][2];
  232. {
  233.     a[pt][0] = x;
  234.     a[pt][1] = y;
  235. }
  236.  
  237. getpoint(a, na, x, y)
  238. register short a[][2];
  239. {
  240.     register short i, bi;
  241.     register long r, br;
  242.  
  243.     for (i = bi = 0, br = 0x7FFFFFFF; i < na; ++i) {
  244.     r = (x-a[i][0])*(x-a[i][0]) + (y-a[i][1])*(y-a[i][1])*3;
  245.     if (r < br) {
  246.         bi = i;
  247.         br = r;
  248.     }
  249.     }
  250.     return(bi);
  251. }
  252.  
  253. clearall()
  254. {
  255.     SetAPen(Rp, 0);
  256.     SetDrMd(Rp, JAM2);
  257.     RectFill(Rp, Ux, Uy, Lx - 1, Ly - 1);
  258.     SetAPen(Rp, 3);
  259.     SetDrMd(Rp, COMPLEMENT);
  260. }
  261.  
  262. #define S10(x)     ((x) >> SHIFTS)
  263. #define S20(x)     ((x) >> (2*SHIFTS))
  264.  
  265. /*
  266.  *  So I can use integer arithmatic, I am defining 512 as 1 (as far
  267.  *  as the mathematics go), which means that I must divide any power
  268.  *  multiplication by 512^(n-1).  E.G. .5^2 = .25 ... to make 256^2
  269.  *  equal 128, I must divide by 512^1
  270.  */
  271.  
  272. static short Array[ONE+4][2];    /* hold points to plot        */
  273.  
  274. drawcurve(a, na)
  275. register short a[][2];
  276. {
  277.     long  mr[4];
  278.     register short n, i, t;
  279.     long tt, ttt;
  280.     short last;
  281.  
  282.     for (i = 1; i < na - 2; ++i) {
  283.     for (t = n = last = 0; t <= ONE; t += Step) {
  284. oncemore:
  285.         tt = t * t;
  286.         ttt= tt* t;
  287.         mr[0] = -S20(ttt/6) + S10(tt/2) - t/2 + ONE/6;
  288.         mr[1] =  S20(ttt/2) - S10(tt)   + ONE*2/3;
  289.         mr[2] = -S20(ttt/2) + S10(tt/2) + t/2 + ONE/6;
  290.         mr[3] =  S20(ttt/6);
  291.  
  292.         Array[n][0] = (mr[0] * a[i-1][0] + mr[1] * a[i][0] + mr[2] * a[i+1][0] + mr[3] * a[i+2][0]) >> SHIFTS;
  293.         Array[n][1] = (mr[0] * a[i-1][1] + mr[1] * a[i][1] + mr[2] * a[i+1][1] + mr[3] * a[i+2][1]) >> SHIFTS;
  294.         if (++n == ONE + 4) {
  295.         --n;
  296.         puts("software error: OVERFLOW");
  297.         }
  298.     }
  299.     if (last == 0 && t > ONE) {
  300.         t = ONE;
  301.         last = 1;
  302.         goto oncemore;
  303.     }
  304.     Move(Rp, Array[0][0], Array[0][1]);
  305.     PolyDraw(Rp, n, Array);
  306.     }
  307. }
  308.  
  309.  
  310. drawpoints(a, is, ie)
  311. register short a[][2];
  312. {
  313.     register short i;
  314.  
  315.     for (i = is; i < ie; ++i) {
  316.     if (Display) {
  317.         char buf[32];
  318.         Move(Rp, a[i][0], a[i][1]);
  319.         Draw(Rp, a[i][0], a[i][1]);
  320.         Move(Rp, a[i][0] - 16, a[i][1] + 4);
  321.         sprintf(buf, "%ld", i);
  322.         Text(Rp, buf, strlen(buf));
  323.     } else {
  324.         Move(Rp, a[i][0] - 2, a[i][1]);
  325.         Draw(Rp, a[i][0] + 2, a[i][1]);
  326.         Move(Rp, a[i][0], a[i][1] - 2);
  327.         Draw(Rp, a[i][0], a[i][1] + 2);
  328.     }
  329.     }
  330. }
  331.  
  332. /*
  333.  *  GADGET ROUTINES!    ------------------------------------------------
  334.  */
  335.  
  336.  
  337. #define NG(nn)    &Gadgets[nn+1]
  338. #define G_YGLOB 1
  339. #define G_XGLOB 2
  340.  
  341. XPI Props[] = {
  342.     { AUTOKNOB|FREEVERT , 0, 0, 0x1FFF, 0x1FFF }
  343. };
  344.  
  345. IM Images[] = {
  346.     { 0,0,2,1,1, NULL, 1, 0, NULL },
  347. };
  348.  
  349. GADGET Gadgets[] = {
  350.     {
  351.     NULL, -15, 11, 15, -19, GADGIMAGE|GADGHCOMP|GRELRIGHT|GRELHEIGHT,
  352.     GADGIMMEDIATE|RIGHTBORDER|RELVERIFY,PROPGADGET,
  353.     (APTR)&Images[0],NULL,NULL,0,(APTR)&Props[0], G_YGLOB, 0
  354.     },
  355. };
  356.  
  357. GADGET *Gc;
  358. long GUx, GUy;
  359.  
  360. init_gadgets(nw, ppo)
  361. NW *nw;
  362. XPI **ppo;
  363. {
  364.     nw->FirstGadget = &Gadgets[0];
  365.     *ppo = &Props[0];
  366. }
  367.  
  368. /*
  369.  *  MENU ROUTINES! -----------------------------------------------------
  370.  */
  371.  
  372. ITEXT Itext[] = {
  373.     { 0,1,JAM2,0,0,NULL,(UBYTE *)"  Move",  NULL },
  374.     { 0,1,JAM2,0,0,NULL,(UBYTE *)"  Add",   NULL },
  375.     { 0,1,JAM2,0,0,NULL,(UBYTE *)"  Delete",NULL },
  376.     { 0,1,JAM2,0,0,NULL,(UBYTE *)"  Cross", NULL },
  377.     { 0,1,JAM2,0,0,NULL,(UBYTE *)"  Number",NULL }
  378. };
  379.  
  380.  
  381. MENUITEM Item0[] = {
  382.     { &Item0[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
  383.       0xFE, (APTR)&Itext[0], NULL, 'M', NULL, NULL
  384.     },
  385.     {
  386.       &Item0[2], 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
  387.       0xFD, (APTR)&Itext[1], NULL, 'A', NULL, NULL
  388.     },
  389.     {
  390.       NULL,    0,16, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
  391.       0xFB, (APTR)&Itext[2], NULL, 'D', NULL, NULL
  392.     }
  393. };
  394.  
  395. MENUITEM Item1[] = {
  396.     { &Item1[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
  397.       0xFE, (APTR)&Itext[3], NULL, 'C', NULL, NULL
  398.     },
  399.     {
  400.       NULL     , 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT,
  401.       0xFD, (APTR)&Itext[4], NULL, 'N', NULL, NULL
  402.     }
  403. };
  404.  
  405.  
  406. MENU Menu[] = {
  407.     { &Menu[1], 0,   0,8*11, 8, MENUENABLED, "Control", &Item0[0] },
  408.     { NULL    , 8*11,0,8*11, 8, MENUENABLED, "Display", &Item1[0] }
  409. };
  410.  
  411. init_menu(win)
  412. WIN *win;
  413. {
  414.     SetMenuStrip(win, &Menu[0]);
  415. }
  416.  
  417. uninit_menu(win)
  418. WIN *win;
  419. {
  420.     ClearMenuStrip(win);
  421. }
  422.  
  423.  
  424.  
  425.